//! @file   lc_numeric_limits.h
//! @brief  
//! @author Sayan Chaliha
//! @date   September, 2011
//!
//! 
#ifndef _LC_NUMERIC_LIMITS_H
#define _LC_NUMERIC_LIMITS_H

#include "libcyan_internal.h"
#include "lc_types.h"

namespace cyan {
  template <typename T>
  typename EnableIf<AreComparable<T>::value, T>::Type CYAN_API
  minimum(const T& value1, const T& value2) {
    if (value1 > value2)
      return value2;
    else
      return value1;
  }

  template <typename T>
  typename EnableIf<AreComparable<T>::value, T>::Type CYAN_API
  maximum(const T& value1, const T& value2) {
    if (value1 > value2)
      return value1;
    else
      return value2;
  }

  template <typename T>
  struct CYAN_API NumericLimits {
    typedef T IntType;

    static typename EnableIf<IsIntegral<T>::value, IntType>::Type
    minimum() {
      if (!typeIsSigned())
        return 0;
      return -(static_cast<IntType>(::pow(2, (sizeof (IntType) * 8 - 1))));
    }

    static typename EnableIf<IsIntegral<T>::value, IntType>::Type
    maximum() {
      if (!typeIsSigned())
        return IntType(-1);
      return (static_cast<IntType>(::pow(2, (sizeof (IntType) * 8) - 1) - 1));
    }

    static typename EnableIf<IsIntegral<T>::value, Bool>::Type
    typeIsSigned() {
      if (IntType(-1) > 0)
        return false;
      return true;
    }
  };

  template <>
  struct CYAN_API NumericLimits<Int8> {
    typedef Int8 IntType;

    static IntType minimum() {
      return IntType(-127 - 1);
    }

    static IntType maximum() {
      return IntType(+127);
    }

    static Bool typeIsSigned() {
      return true;
    }
  };

  template <>
  struct CYAN_API NumericLimits<UInt8> {
    typedef UInt8 IntType;

    static IntType minimum() {
      return IntType(0);
    }

    static IntType maximum() {
      return IntType(255);
    }

    static Bool typeIsSigned() {
      return false;
    }
  };

  template <>
  struct CYAN_API NumericLimits<Int16> {
    typedef Int16 IntType;

    static IntType minimum() {
      return IntType(-32767 - 1);
    }

    static IntType maximum() {
      return IntType(+32767);
    }

    static Bool typeIsSigned() {
      return true;
    }
  };

  template <>
  struct CYAN_API NumericLimits<UInt16> {
    typedef UInt16 IntType;

    static IntType minimum() {
      return IntType(0U);
    }

    static IntType maximum() {
      return IntType(65535U);
    }

    static Bool typeIsSigned() {
      return false;
    }
  };

  template <>
  struct CYAN_API NumericLimits<Int32> {
    typedef Int32 IntType;

    static IntType minimum() {
      return IntType(-2147483647 - 1);
    }

    static IntType maximum() {
      return IntType(+2147483647);
    }

    static Bool typeIsSigned() {
      return true;
    }
  };

  template <>
  struct CYAN_API NumericLimits<UInt32> {
    typedef UInt32 IntType;

    static IntType minimum() {
      return IntType(0U);
    }

    static IntType maximum() {
      return IntType(4294967295U);
    }

    static Bool typeIsSigned() {
      return false;
    }
  };

  template <>
  struct CYAN_API NumericLimits<Int64> {
    typedef Int64 IntType;

    static IntType minimum() {
      //BUG: For some reason, the compiler throws an error if a literal of value
      // -9223372036854775807L - 1L is specified instead of the calculated
      // value. This occurs only in i386 architecture mode.
      return -(implicit_cast<IntType>(::pow(2, (sizeof (IntType) * 8 - 1))));
    }

    static IntType maximum() {
      //BUG: For some reason, the compiler throws an error if a literal of value
      // 9223372036854775807L is specified instead of the calculated value.
      // This occurs only in i386 architecture mode.
      return (static_cast<IntType>(::pow(2, (sizeof (IntType) * 8 - 1)) - 1));
    }

    static Bool typeIsSigned() {
      return true;
    }
  };

  template <>
  struct CYAN_API NumericLimits<UInt64> {
    typedef UInt64 IntType;

    static IntType minimum() {
      return IntType(0UL);
    }

    static IntType maximum() {
      return IntType(-1);
    }

    static Bool typeIsSigned() {
      return false;
    }
  };
}

#endif /* _LC_NUMERIC_LIMITS_H */
